package com.app.util.ant;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;

public class AntPool<T> {

	private ThreadPoolExecutor pool;

	private final LinkedBlockingQueue<Ant<T>> freeQueue = new LinkedBlockingQueue<Ant<T>>();

	private int maxActiveCount;
	private volatile int size;
	private Class<? extends Ant<T>> antClass;

	public AntPool(int maxActiveCount, Class<? extends Ant<T>> antClass) {
		this.maxActiveCount = maxActiveCount;
		this.antClass = antClass;
		size = 0;
		pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(maxActiveCount);
	}

	public synchronized final void execute(T data) throws AntException {
		if (pool.isTerminating()) {
			throw new AntException("AntPool is terminating.");
		}
		if (pool.isTerminated()) {
			throw new AntException("AntPool is terminated.");
		}
		Ant<T> ant;
		if (freeQueue.size() > 0 || size >= maxActiveCount) {
			try { 
				ant = freeQueue.take();
			} catch (InterruptedException e) {
				throw new AntException(e);
			}
		} else {
			size++;
			try {
				ant = antClass.newInstance();
			} catch (Exception e) {
				throw new AntException(e);
			}
			ant.pool = this;
		}
		ant.setObject(data);
		pool.execute(ant);
	}

	void release(Ant<T> ant) {
		freeQueue.add(ant);
	}

	public int getMaxActiveCount() {
		return maxActiveCount;
	}

	public Class<? extends Ant<T>> getAntClass() {
		return antClass;
	}

	public int getActiveCount() {
		return pool.getActiveCount();
	}

	public long getTaskCount() {
		return pool.getTaskCount();
	}

	public synchronized void shutdown() {
		pool.shutdown();
	}

	public boolean isTerminating() {
		return pool.isTerminating();
	}

	public boolean isTerminated() {
		return pool.isTerminated();
	}

}
